#ifndef __MY_DATA_HPP__
#define __MY_DATA_HPP__

#include <iostream>
#include <unordered_map>
#include <pthread.h>
#include "util.hpp"
#include "config.hpp"

namespace cloud
{
    /*数据信息类*/
    typedef struct BackupInfo
    {
        bool _pack_flag;//标记当前文件是否被压缩存储
        size_t _fsize;//记录文件大小
        time_t _atime;//记录文件最近一次访问时间
        time_t _mtime;//记录文件最近一次修改时间
        std::string _real_path;//记录文件真实存放路径
        std::string _pack_path;//记录文件压缩存放路径
        std::string _url;//记录文件访问url

        /*根据真实文件存放路径，填充BackupInfo字段*/
        bool NewBackupInfo(const std::string& real_path)
        {
            FileUtil fu(real_path);
            if(fu.Exists()==false)
            {
                printf("new backup info,file not exists\n");
                return false;
            }

            //1.获取配置文件对应信息
            Config* cfg=Config::GetInstance();
            std::string pack_dir=cfg->GetPackDir();
            std::string pack_suffix=cfg->GetPackFileSuffix();
            std::string download_prefix=cfg->GetDownloadPrefix();

            //2.填充当前文件信息字段
            _pack_flag=false;
            _fsize=fu.FileSize();
            _atime=fu.LastATime();
            _mtime=fu.LastMTime();
            _real_path=real_path;
            _pack_path=pack_dir+fu.FileName()+pack_suffix;
            _url=download_prefix+fu.FileName();
            return true;
        }
        
    } BackupInfo;

    /*数据信息管理类*/
    class DataManager
    {
    public:
        DataManager()
        {
            //1.初始化_backup_file信息
            Config* cfg=Config::GetInstance();
            _backup_file=cfg->GetBackupFile();

            //2.初始化读写锁
            pthread_rwlock_init(&_rwlock,nullptr);
        }

        /*启动时，一次性加载备份文件信息*/
        bool InitLoad()
        {
            //1.形成FileUtil对象
            FileUtil fu(_backup_file);
            if(fu.Exists()==false)
            {
                return true;
            }

            //2.读取备份文件全部内容
            std::string body;
            if(fu.GetContent(&body)==false)
            {
                printf("init load,get content failed\n");
                return false;
            }
            if(body.empty()==true) return true;

            //3.反序列json格式数据
            Json::Value root;
            JsonUtil::UnSerialize(body,&root);

            //4.加载备份文件信息
            for(int i=0;i<root.size();i++)
            {
                BackupInfo info;
                info._pack_flag=root[i]["pack_flag"].asBool();
                info._fsize=root[i]["fsize"].asInt64();
                info._atime=root[i]["atime"].asInt64();
                info._mtime=root[i]["mtime"].asInt64();
                info._real_path=root[i]["real_path"].asString();
                info._pack_path=root[i]["pack_path"].asString();
                info._url=root[i]["url"].asString();
                Insert(info);
            }

            return true;
        }

        /*将内存中管理起来的Hash数据持久化到磁盘中*/
        bool Storage()
        {
            //1.获取_table中全部BackupInfo信息
            std::vector<BackupInfo> arry;
            GetAll(&arry);

            //2.序列化组织成json格式数据
            Json::Value root;
            for(auto& iter:arry)
            {
                Json::Value val;
                val["pack_flag"]=iter._pack_flag;
                val["fsize"]=(Json::Int64)iter._fsize;
                val["atime"]=(Json::Int64)iter._atime;
                val["mtime"]=(Json::Int64)iter._mtime;
                val["real_path"]=iter._real_path;
                val["pack_path"]=iter._pack_path;
                val["url"]=iter._url;
                root.append(val);
            }

            std::string body;
            JsonUtil::Serialize(root,&body);

            //3.写入到备份文件中
            FileUtil fu(_backup_file);
            fu.SetContent(body);
            return true;
        }

        /*将val对象插入到_table中管理*/
        bool Insert(const BackupInfo& val)
        {
            pthread_rwlock_wrlock(&_rwlock);
            _table[val._url]=val;
            pthread_rwlock_unlock(&_rwlock);
            Storage();//每次插入数据都第一时间持久到磁盘上
            return true;
        }

        /*更新指定url的BackupInfo*/
        bool Update(const BackupInfo& val)
        {
            pthread_rwlock_wrlock(&_rwlock);
            _table[val._url]=val;
            pthread_rwlock_unlock(&_rwlock);
            Storage();//每次更新数据都第一时间持久到磁盘上
            return true;
        }

        /*根据指定url获取BackupInfo信息*/
        bool GetOneByURL(const std::string& url,BackupInfo* val)
        {
            pthread_rwlock_wrlock(&_rwlock);
            auto iter=_table.find(url);
            if(iter==_table.end())
            {
                pthread_rwlock_unlock(&_rwlock);
                return false;
            }

            *val=iter->second;
            pthread_rwlock_unlock(&_rwlock);
            return true;
        }

        /*根据指定的真实文件路径获取BackupInfo信息*/
        bool GetOneByRealPath(const std::string& real_path,BackupInfo* val)
        {
            pthread_rwlock_wrlock(&_rwlock);
            for(auto& iter:_table)
            {
                if(iter.second._real_path==real_path)
                {
                    *val=iter.second;
                    pthread_rwlock_unlock(&_rwlock);
                    return true;
                }
            }

            pthread_rwlock_unlock(&_rwlock);
            return false;
        }

        /*获取全部BackupInfo信息*/
        bool GetAll(std::vector<BackupInfo>* arry)
        {
            pthread_rwlock_wrlock(&_rwlock);
            for(auto& iter:_table)
            {
                arry->push_back(iter.second);
            }
            pthread_rwlock_unlock(&_rwlock);
            return true;
        }

        ~DataManager()
        {
            pthread_rwlock_destroy(&_rwlock);
        }

    private:
        std::string _backup_file;//记录文件信息备份文件
        pthread_rwlock_t _rwlock;//读写锁保护
        std::unordered_map<std::string,BackupInfo> _table;//建立url与BackupInfo唯一映射关系
    };
}

#endif